package cn.net.wanji.task;

import cn.hutool.core.date.DateUtil;
import cn.net.wanji.config.ApplicationConfig;
import cn.net.wanji.config.CommonParamConfig;
import cn.net.wanji.entity.FileCount;
import cn.net.wanji.entity.VehicleRsuInfo;
import cn.net.wanji.mapper.DataReceiveMapper;
import cn.net.wanji.utils.DateUtils;
import cn.net.wanji.utils.DiskUtils;
import cn.net.wanji.utils.LogUtils;
import cn.net.wanji.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;

import javax.annotation.Resource;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author guodejun
 * @createTime 2022/12/2 11:06
 * @updateTime 2024/01/10 11:06 yangliang
 * @description
 */
//@Log4j2
@Configuration      // 1.主要用于标记配置类，兼备Component的效果。
@EnableAsync   //单独线程跑
@EnableScheduling
@Slf4j(topic = "定时任务删除图片【UpdateFileDataByTime】")// 2.开启定时任务
public class UpdateFileDataByTime {
    private final static Logger deleteFileLogger = LoggerFactory.getLogger("file");
    @Value("${file.no-exception-data-save-day-num}")
    private int noExceptionDataSaveDayNum;
    @Value("${file.exception-data-save-day-num}")
    private int exceptionDataSaveDayNum;
    @Resource
    private ApplicationConfig applicationConfig;
    @Resource
    private FolderDeletion folderDeletion;
    ExecutorService executorService = Executors.newCachedThreadPool();
    @Resource
    private DataReceiveMapper dataReceiveMapper;
    private static final int THREAD_POOL_SIZE = 10;
    ExecutorService executorServiceFile = Executors.newFixedThreadPool(THREAD_POOL_SIZE);


    /**
     * 每天凌晨2点进行无异常非结构化数据清除
     *
     * @throws Exception
     */
//    @Scheduled(cron = "0 0 2 * * ?")0 0 2 * * ?
//    @Scheduled(cron = "0/12 * * * * *")
    @Scheduled(cron = "${spring.task.scheduling.configureTasks}")
    private void configureTasks() {
        try {
            clearAuditIsNormalImageByDate();
            clearAuditAnomaliesImageByDate();
        } catch (Exception e) {
            LogUtils.errorLog(e);
        }
    }

    //    @Scheduled(cron = "0/30 * * * * *")
    //30分钟执行一次

    //    @Scheduled(cron = "0 */2 * * * *")
    @Scheduled(cron = "${spring.task.scheduling.cron}")
//    @Scheduled(cron = "0/12 * * * * *")
    public void cleanupEvery30Seconds() {
        //已用磁盘占比
        Double discPercentage = applicationConfig.getDiscPercentage();
        Double filePercentage = DiskUtils.getMountPointAndDiskUsage(applicationConfig.getFileSavePath("1"));
        while (filePercentage > discPercentage) {

            String time = cleanupEvery30SecondsDelete_AUDIT_IS_NORMAL();
//            filePercentage = viewDiskCapacity(rootDirectory);
            filePercentage = DiskUtils.getMountPointAndDiskUsage(applicationConfig.getFileSavePath("1"));
            if (StringUtils.isEmpty(time)) {
                deleteFileLogger.info("end clear cleanupEvery30Seconds auditIsNormal file data" + "磁盘使用率： " + filePercentage);
                //删除日志
                String logPath = applicationConfig.getLogPath();

                folderDeletion.deleteFoldersByDescendingDate(logPath);
//                double errPercentage = viewDiskCapacity(rootDirectory);
                double errPercentage = DiskUtils.getMountPointAndDiskUsage(applicationConfig.getFileSavePath("1"));
                if (errPercentage > discPercentage) {
                    //删除异常数据
                    List<FileCount> fileCounts = dataReceiveMapper.selectFileCountAuditAnomaliesEarliest();

                    if (StringUtils.isNull(fileCounts) || fileCounts.size() == 0) {
                        deleteFileLogger.info("end clear cleanupEvery30Seconds AUDIT_ANOMALIES file data" + "磁盘使用率：" + errPercentage);
                        break;
                    }
                    String errTime = fileCounts.get(0).getTime();
                    String strFormatYyyyMmdd = DateUtils.getStrFormatYyyyMmdd(errTime);
                    String strFormatYyyy_Mm_dd = DateUtils.getStrFormatYyyy_Mm_dd(errTime);
                    deleteDirectory(applicationConfig.getFileSavePath("1") + File.separator + CommonParamConfig.AUDIT_ANOMALIES + File.separator + strFormatYyyyMmdd);
                    deleteFileLogger.info("delete cleanupEvery30Seconds auditAnomalies file " + applicationConfig.getFileSavePath("1") + File.separator + CommonParamConfig.AUDIT_ANOMALIES + File.separator + strFormatYyyyMmdd + "磁盘使用率：" + errPercentage);
                    dataReceiveMapper.deleteFileCountByDate(strFormatYyyy_Mm_dd);
                }

            }


        }

    }

    /*
     * 根据磁盘路径删除超过阈值正常数据
     * */
    public String cleanupEvery30SecondsDelete_AUDIT_IS_NORMAL() {
        List<FileCount> fileCounts = dataReceiveMapper.selectFileCountAuditIsNormalEarliest();
        List<String> ids = new ArrayList<>();
        if (StringUtils.isNotNull(fileCounts) && fileCounts.size() == 0) {
            return "";
        }
        String time = "";
        for (FileCount fileCount : fileCounts) {
            ids.add(fileCount.getId());
            time = fileCount.getTime();
            String fileSavePath = applicationConfig.getFileSavePath(fileCount.getId());
// 使用endsWith()方法检查字符串是否以斜杠 "/" 结尾
            if (fileSavePath.endsWith("/")) {
                // 使用substring()方法去除末尾的斜杠
                fileSavePath = fileSavePath.substring(0, fileSavePath.length() - 1);
            }
            // 删除之前旧数据文件夹
            deleteDirectory(fileSavePath + File.separator + fileCount.getId());

        }
        deleteFileLogger.info("delete cleanupEvery30Seconds old version AUDIT_IS_NORMAL file " + fileCounts.get(0).toString());

        String strFormatYyyyMmdd = DateUtils.getStrFormatYyyyMmdd(time);
        //删除新数据文件夹
        double fileNewPercentage = DiskUtils.getMountPointAndDiskUsage(applicationConfig.getFileSavePath("1"));
        Double discPercentage = applicationConfig.getDiscPercentage();
        if (fileNewPercentage > discPercentage) {
            String fileSavePath = applicationConfig.getFileSavePath(strFormatYyyyMmdd);
            // 使用endsWith()方法检查字符串是否以斜杠 "/" 结尾
            if (fileSavePath.endsWith("/")) {
                // 使用substring()方法去除末尾的斜杠
                fileSavePath = fileSavePath.substring(0, fileSavePath.length() - 1);
            }
            //删除正常数据
            deleteDirectory(fileSavePath + File.separator + CommonParamConfig.AUDIT_IS_NORMAL + File.separator + strFormatYyyyMmdd);
            deleteFileLogger.info("delete cleanupEvery30Seconds auditIsNormal new file " + fileSavePath + File.separator + CommonParamConfig.AUDIT_IS_NORMAL + File.separator + strFormatYyyyMmdd);
//        dataReceiveMapper.deleteFileCountByDate(time);
            bathDeleteFilecountByIds(ids);
            deleteFileLogger.info("delete cleanupEvery30Seconds auditIsNormal new file filecount " + fileCounts.get(0).toString());
        } else {
            //删除旧数据数据file_count
            bathDeleteFilecountByIds(ids);
            deleteFileLogger.info("delete cleanupEvery30Seconds old version AUDIT_IS_NORMAL filecount " + fileCounts.get(0).toString());
        }

        return time;
    }

    /*
     * 多线程clickhouse根据主键id删除方法
     * */
    private void bathDeleteFilecountByIds(List<String> ids) {
        if (ids.size() <= 1000) {
            executorService.submit(() -> {
                try {
                    dataReceiveMapper.batchDeleteFileCountAuditIsNormalByIds(ids);
                } catch (Exception e) {
                    LogUtils.errorLog(e);
                }
            });
        } else {
            int batchSize = 1000;
            int numBatches = (int) Math.ceil((double) ids.size() / batchSize);

            for (int i = 0; i < numBatches; i++) {
                int fromIndex = i * batchSize;
                int toIndex = Math.min((i + 1) * batchSize, ids.size());
                List<String> batch = ids.subList(fromIndex, toIndex);

                executorService.submit(() -> {
                    try {
                        dataReceiveMapper.batchDeleteFileCountAuditIsNormalByIds(batch);
                    } catch (Exception e) {
                        LogUtils.errorLog(e);
                    }
                });
            }
        }
    }


    private String getRootDirectory(String path) {
        Path fullPath = Paths.get(path);
//        Path root = fullPath.getRoot();
        Path parent = fullPath.getParent();
        return parent.toString();
    }


    /**
     * 获取回溯时间
     */
    private String[] getDate(int offset) {
        String[] nowDate = LocalDateTime.now().toString().split("T");
        String split = nowDate[0];
        Date dateTime = DateUtil.offsetDay(DateUtil.parse(split), -offset);
        return new String[]{dateTime.toString(), nowDate[0] + " " + nowDate[1]};
    }

    /*
     * 判断文件夹是否存在
     * */
    public static boolean doesFolderExist(String folderPath) {
        Path folder = Paths.get(folderPath);
        return Files.exists(folder) && Files.isDirectory(folder);
    }


    public static void deleteDirectory(String path) {
        File file = new File(path);
        if (!file.exists()) {
            return;
        }
        if (file.isFile()) {
            file.delete();
            // 清理文件
        } else {

            File[] list = file.listFiles();
            if (list != null) {
                for (File f : list) {
                    deleteDirectory(f.getAbsolutePath());
                }
                file.delete();//清理目录
            }
        }
    }

    /*
     * 根据配置天数删除正常数据图片
     * */
    private void clearAuditIsNormalImageByDate() throws Exception {
        // 获取 n 天前无异常的数据
        String[] date = getDate(noExceptionDataSaveDayNum);
//        deleteFileLogger.info("start clear no exception file data, now time: " + date[1] + " clear time: " + date[0]);
        List<FileCount> fileCounts = dataReceiveMapper.selectFileCountByDate(date[0]);
        //判断file_count表中记录图片是否已经删除
        if (StringUtils.isNull(fileCounts) || fileCounts.size() == 0) {
            return;
        }
        // 查询 n 天前的无异常数据
        List<String> recordIds = dataReceiveMapper.selectNoExceptionDataByDate(date[0]);
        int count = 0;
        for (String recordId : recordIds) {
            String fileSavePath = applicationConfig.getFileSavePath(recordId);

            // 删除文件夹
//            deleteDirectory(fileSavePath + File.separator + recordId);
            executorServiceFile.submit(() -> deleteDirectory(fileSavePath + File.separator + recordId));
            if (count == 0 || count == recordIds.size() - 2) {
                deleteFileLogger.info("delete old no exception file first: " + recordIds.get(0).toString() + " and end :" + recordIds.get(recordIds.size() - 1).toString()+" size: "+recordIds.size());

            }
            count++;
        }

//        deleteFileLogger.info("delete old no exception file " + recordIds.toString());
        deleteFileLogger.info("end clear old no exception file data");
        for (FileCount fileCount : fileCounts) {
            String time = fileCount.getTime();
            String strFormatYyyyMmdd = time.replace("-", "");
            String fileSavePath = applicationConfig.getFileSavePath("1");
            // 使用endsWith()方法检查字符串是否以斜杠 "/" 结尾
            if (fileSavePath.endsWith("/")) {
                // 使用substring()方法去除末尾的斜杠
                fileSavePath = fileSavePath.substring(0, fileSavePath.length() - 1);
            }
            //删除正常数据
            //判断文件夹是否存在
            boolean b = doesFolderExist(fileSavePath + File.separator + CommonParamConfig.AUDIT_IS_NORMAL + File.separator + strFormatYyyyMmdd);
            if (!b) {
                //不存在
                continue;
            }
            deleteDirectory(fileSavePath + File.separator + CommonParamConfig.AUDIT_IS_NORMAL + File.separator + strFormatYyyyMmdd);
            deleteFileLogger.info("delete clearAuditIsNormalImageByDate auditIsNormal file " + fileSavePath + File.separator + CommonParamConfig.AUDIT_IS_NORMAL + File.separator + strFormatYyyyMmdd);
        }
//        dataReceiveMapper.deleteFileCountByDate(date[0]);
        bathDeleteFilecountByIds(recordIds);
        deleteFileLogger.info("end clear no exception file data");
    }


    public static void main(String[] args) {
        // 查询 n 天前的无异常数据
//        ExecutorService executorService = Executors.newFixedThreadPool(THREAD_POOL_SIZE);
//        List<String> recordIds = new ArrayList<>();
//        for (int i = 0; i < 3000000; i++) {
//            recordIds.add("G00044100400531001020231201000010314000003" + String.valueOf(i));
//        }
//        System.out.println(recordIds);
//        System.out.println("recordIds:" + recordIds.size());
//        int count = 0;
//        for (String recordId : recordIds) {
//            // 提交删除任务到线程池
////            executorService.submit(() -> deleteDirectory("D:\\河南部署\\tests" + File.separator + recordId));
//            deleteDirectory("D:\\河南部署\\tests" + File.separator + recordId);
//            if (count == 0 || count == recordIds.size() - 2) {
//                deleteFileLogger.info("delete old no exception file first: " + recordIds.get(0).toString() + " and end :" + recordIds.get(recordIds.size() - 1).toString());
//
//            }
//            count++;
//        }
        String myString = "example/";

        // 使用endsWith()方法检查字符串是否以斜杠 "/" 结尾
        if (myString.endsWith("/")) {
            // 使用substring()方法去除末尾的斜杠
            myString = myString.substring(0, myString.length() - 1);
        }
    }



    /*
     * 根据配置天数删除异常数据图片
     * */
    private void clearAuditAnomaliesImageByDate() throws Exception {
        // 获取 n 天前异常的数据
        String[] errdate = getDate(exceptionDataSaveDayNum);
//        deleteFileLogger.info("start clear no exception file data, now time: " + errdate[1] + " clear time: " + errdate[0]);
        List<FileCount> fileCounts = dataReceiveMapper.selectFileCountByDate(errdate[0]);
        //判断file_count表中记录图片是否已经删除
        if (StringUtils.isNull(fileCounts) || fileCounts.size() == 0) {
            return;
        }
        // 查询 n 天前的异常数据
        List<String> recordIds = dataReceiveMapper.selectExceptionByDate(errdate[0]);
        int count = 0;
        for (String recordId : recordIds) {
            String fileSavePath = applicationConfig.getFileSavePath(recordId);
            // 使用endsWith()方法检查字符串是否以斜杠 "/" 结尾
            if (fileSavePath.endsWith("/")) {
                // 使用substring()方法去除末尾的斜杠
                fileSavePath = fileSavePath.substring(0, fileSavePath.length() - 1);
            }
            // 删除文件夹
            deleteDirectory(fileSavePath + File.separator + recordId);
            if (count == 0 || count == recordIds.size() - 2) {
                deleteFileLogger.info("delete old  exception file first: " + recordIds.get(0).toString() + " and end :" + recordIds.get(recordIds.size() - 1).toString());

            }
            count++;
        }
        deleteFileLogger.info("end clear old  exception file data" + recordIds.toString());

        for (FileCount fileCount : fileCounts) {
            String time = fileCount.getTime();
            String strFormatYyyyMmdd = time.replace("-", "");
            String fileSavePath = applicationConfig.getFileSavePath("1");
            // 使用endsWith()方法检查字符串是否以斜杠 "/" 结尾
            if (fileSavePath.endsWith("/")) {
                // 使用substring()方法去除末尾的斜杠
                fileSavePath = fileSavePath.substring(0, fileSavePath.length() - 1);
            }
            //删除异常数据
            //判断文件夹是否存在
            boolean b = doesFolderExist(fileSavePath + File.separator + CommonParamConfig.AUDIT_ANOMALIES + File.separator + strFormatYyyyMmdd);
            if (!b) {
                //不存在
                continue;
            }
            deleteDirectory(fileSavePath + File.separator + CommonParamConfig.AUDIT_ANOMALIES + File.separator + strFormatYyyyMmdd);
            deleteFileLogger.info("delete clearAuditAnomaliesImageByDate auditAnomalies file " + fileSavePath + File.separator + CommonParamConfig.AUDIT_ANOMALIES + File.separator + strFormatYyyyMmdd);
        }
//        dataReceiveMapper.deleteFileCountByDate(errdate[0]);
        bathDeleteFilecountByIds(recordIds);
        deleteFileLogger.info("end clear exception file data");
    }

}